﻿namespace Mp3Observer.Common
{
    using System.Text;

    /// <summary>
    /// Copied from http://www.blackwasp.co.uk/Soundex.aspx
    /// </summary>
    /// <remarks>
    /// TODO : Add to Linq search algorithm!
    /// </remarks>
    /// <example>
    /// <code>
    ///    string value1 = "Smith";
    ///    string value2 = "Smythe";
    ///    Soundex soundex = new Soundex();
    ///    Console.WriteLine(soundex.GetSoundex(value1));      // Outputs "S530"
    ///    Console.WriteLine(soundex.GetSoundex(value2));      // Outputs "S530"
    ///    Console.WriteLine(soundex.Compare(value1, value2)); // Outputs "4"
    /// </code>
    /// </example>
    public class Soundex
    {
        /// <summary>
        /// Compares the specified value1.
        /// </summary>
        /// <param name="value1">The value1.</param>
        /// <param name="value2">The value2.</param>
        /// <returns></returns>
        public int Compare(string value1, string value2)
        {
            int matches = 0;
            string soundex1 = GetSoundex(value1);
            string soundex2 = GetSoundex(value2);

            for (int i = 0; i < 4; i++)
                if (soundex1[i] == soundex2[i]) matches++;

            return matches;
        }

        /// <summary>
        /// Gets the soundex.
        /// </summary>
        /// <param name="value">The value.</param>
        /// <returns></returns>
        public string GetSoundex(string value)
        {
            value = value.ToUpper();
            var soundex = new StringBuilder();
            foreach (char ch in value)
            {
                if (char.IsLetter(ch))
                    AddCharacter(soundex, ch);
            }
            RemovePlaceholders(soundex);
            FixLength(soundex);
            return soundex.ToString();
        }

        /// <summary>
        /// Adds the character.
        /// </summary>
        /// <param name="soundex">The soundex.</param>
        /// <param name="ch">The ch.</param>
        private void AddCharacter(StringBuilder soundex, char ch)
        {
            if (soundex.Length != 0)
                AddSoundexDigit(soundex, ch);
            else
                soundex.Append(ch);
        }

        /// <summary>
        /// Fixes the length.
        /// </summary>
        /// <param name="soundex">The soundex.</param>
        private void FixLength(StringBuilder soundex)
        {
            int length = soundex.Length;
            if (length < 4)
                soundex.Append(new string('0', 4 - length));
            else
                soundex.Length = 4;
        }

        /// <summary>
        /// Adds the soundex digit.
        /// </summary>
        /// <param name="soundex">The soundex.</param>
        /// <param name="ch">The ch.</param>
        private void AddSoundexDigit(StringBuilder soundex, char ch)
        {
            char code = GetSoundexDigit(ch.ToString());
            if (code != soundex[soundex.Length - 1])
                soundex.Append(code);
        }

        /// <summary>
        /// Removes the placeholders.
        /// </summary>
        /// <param name="soundex">The soundex.</param>
        private void RemovePlaceholders(StringBuilder soundex)
        {
            soundex.Replace(".", "");
        }

        /// <summary>
        /// Gets the soundex digit.
        /// </summary>
        /// <param name="ch">The ch.</param>
        /// <returns></returns>
        private char GetSoundexDigit(string ch)
        {
            if ("BFPV".Contains(ch))
                return '1';
            else if ("CGJKQSXZ".Contains(ch))
                return '2';
            else if ("DT".Contains(ch))
                return '3';
            else if (ch == "L")
                return '4';
            else if ("MN".Contains(ch))
                return '5';
            else if (ch == "R")
                return '6';
            else
                return '.';
        }
    }
}
